home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr47
/
dos6mm.zip
/
UMASCAN.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-03-31
|
49KB
|
1,063 lines
;****************************************************************************
; UMASCAN scans the PC's address space from 640K to 1MB and lists the ROM,
; RAM, Video RAM, EMS pages, and unused areas that it finds. Its syntax is:
;
; UMASCAN [/M]
;
; where /M forces it to run in monochrome mode (useful on laptops). The
; ROM it reports may be adapter ROM or system ROM. The RAM it reports may
; be adapter RAM or UMB RAM. Any unused areas it identifies are candidates
; to be converted to UMBs using DOS's EMM386.EXE driver.
;****************************************************************************
code segment
assume cs:code,ds:code
org 100h
begin: jmp main
header1 db "UMASCAN 1.1 Copyright (c) 1993 Jeff Prosise",0
header2 db "From: PC Magazine DOS 6 Memory Management with "
db "Utilities",0
helpmsg db "Draws a map profiling the upper memory area and "
db "identifies unused",13,10
db "address space that may be converted to upper memory "
db "blocks.",13,10,13,10
db "UMASCAN [/M]",13,10,13,10
db " /M Use monochrome video attributes.",13,10,13,10
db "Run UMASCAN when EMM386.EXE is not loaded to "
db "identify adapter RAM.",13,10,"$"
errmsg1 db "Syntax: UMASCAN [/M]",13,10,"$"
map db 192 dup (32) ;Upper memory map
colors label byte ;Color video attributes
border_color db 1Fh
back_color db 3Fh
fore_color db 1Fh
rom_color db 5Bh
ram_color db 4Fh
video_color db 2Eh
ems_color db 3Fh
unk_color db 7Fh
note_color db 07h
title_color db 0Fh
shadow_color db 07h
mono_colors db 70h,07h,7Fh,0Fh,0Fh,0Fh ;Monochrome attributes
db 0Fh,0Fh,07h,0Fh,07h
devname db "EMMXXXX0" ;EMM device name
video_segment dw 0B800h ;Current video segment
video_offset dw ? ;Video buffer start address
line_length dw ? ;Bytes per video line
maxrow db 24 ;Highest row number
text1 db "F000",0
text2 db "E000",0
text3 db "D000",0
text4 db "C000",0
text5 db "B000",0
text6 db "A000",0
text7 db 0Ah,"0",0Ch,"1",0Eh,"2",10h,"3"
db 13h,"4",15h,"5",17h,"6",19h,"7"
db 1Ch,"8",1Eh,"9",20h,"A",22h,"B"
db 25h,"C",27h,"D",29h,"E",2Bh,"F"
text8 db " LEGEND ",0
text9 db "RRRR",0
text10 db "++++",0
text11 db "VVVV",0
text12 db "EEEE",0
text12x db "UUUU",0
text13 db "ROM",0
text14 db "RAM",0
text15 db "Video Buffer",0
text16 db "EMS Page Frame",0
text17 db "Unknown",0
text18 db "1. RRRR indicates adapter ROM or system board "
db "ROM.",0
text19 db "2. ++++ indicates adapter RAM or UMB RAM created by "
db "a 386 memory manager.",0
text20 db "3. Areas marked UUUU usually contain a mixture of "
db "ROM, RAM, and unused space.",0
text21 db " These areas generally should not be converted to "
db "upper memory blocks.",0
text22 db "4. Unmarked areas may safely be converted to upper "
db "memory blocks.",0
text23 db " Press Esc to exit ",0
;****************************************************************************
; Procedure MAIN
;****************************************************************************
main proc near
cld ;Clear direction flag
mov si,81h ;Point SI to command line
call scanhelp ;Scan for "/?" switch
jnc main1 ;Branch if not found
mov ah,09h ;Display help text and exit
mov dx,offset helpmsg ;with ERRORLEVEL=0
int 21h
mov ax,4C00h
int 21h
;
; Modify the color palette if a /M switch was included.
;
main1: call findchar ;Advance to next character
jc main3 ;Branch if there is none
lodsw ;Get the next two characters
and ah,0DFh ;Capitalize the second one
cmp ax,4D2Fh ;Error if other than /M
je main2
mov ah,9 ;Display error message
mov dx,offset errmsg1
int 21h
mov ax,4C01h ;Exit with ERRORLEVEL=1
int 21h
main2: call change_colors ;Change color palette to mono
;
; Draw the screen and terminate when a key is pressed.
;
main3: call init_video ;Initialize video
mov ah,03h ;Get the cursor type
mov bh,00h ;from the BIOS
int 10h
push cx ;Save it
mov ah,01h ;Hide the cursor
mov ch,20h
int 10h
call draw_screen ;Paint the screen
call build_table ;Build the map table
call draw_map ;Display the memory map
main4: mov ah,00h ;Pause until Esc is pressed
int 16h
cmp al,27
jne main4
call clear_screen ;Clear the screen
mov ah,0Fh ;Get the active page number
int 10h
mov ah,02h ;Home the cursor to the upper
mov dx,0000h ;left corner of the screen
int 10h
mov ah,01h ;Make the cursor visible
pop cx ;again
int 10h
mov ax,4C00h ;Exit with ERRORLEVEL=0
int 21h
main endp
;****************************************************************************
; SCANHELP scans the command line for a /? switch. If found, carry returns
; set and SI contains its offset. If not found, carry returns clear.
;****************************************************************************
scanhelp proc near
push si ;Save SI
scanloop: lodsb ;Get a character
cmp al,0Dh ;Exit if end of line
je scan_exit
cmp al,"?" ;Loop if not "?"
jne scanloop
cmp byte ptr [si-2],"/" ;Loop if not "/"
jne scanloop
add sp,2 ;Clear the stack
sub si,2 ;Adjust SI
stc ;Set carry and exit
ret
scan_exit: pop si ;Restore SI
clc ;Clear carry and exit
ret
scanhelp endp
;****************************************************************************
; FINDCHAR advances SI to the next non-white space character. On return,
; carry set indicates EOL was encountered; carry clear indicates it was not.
;****************************************************************************
findchar proc near
lodsb ;Get the next character
cmp al,09h ;Loop if tab
je findchar
cmp al,20h ;Loop if space
je findchar
cmp al,2Ch ;Loop if comma
je findchar
dec si ;Point SI to the character
cmp al,0Dh ;Exit with carry set if end
je eol ;of line is reached
clc ;Clear carry and exit
ret
eol: stc ;Set carry and exit
ret
findchar endp
;****************************************************************************
; CHANGE_COLORS copies monochrome attribute values to the color table.
; On entry, both DS and ES must point to the code segment.
;****************************************************************************
change_colors proc near
mov si,offset mono_colors
mov di,offset colors
mov cx,11
rep movsb
ret
change_colors endp
;****************************************************************************
; INIT_VIDEO initializes the variables used by the program's video output
; routines and makes sure we're in an 80-column text mode.
;****************************************************************************
init_video proc near
mov ax,40h ;Point ES to the BIOS data
mov es,ax ;area
mov al,es:[49h] ;Get video mode in AL
cmp al,0Fh ;Branch if it's other than
jne init1 ;0Fh (EGA mono graphics)
mov ax,0007h ;Switch to mode 7 (80-column
int 10h ;monochrome text)
jmp short init2 ;Branch and change colors
init1: cmp al,7 ;Branch if it's other than
jne init3 ;mode 7 (monochrome text)
init2: mov ax,cs ;Point ES back to the code
mov es,ax ;segment
call change_colors ;Change color palette to mono
mov ax,40h ;Point ES back to the BIOS
mov es,ax ;data area
mov video_segment,0B000h ;Change to monochrome segment
jmp short init5 ;Branch past mode check
init3: cmp al,2 ;Reset the video mode if the
jb init4 ;current video mode number
cmp al,3 ;is less than 2 or greater
jbe init5 ;than 3
init4: mov ax,0003h ;Switch to mode 3 (80-column
int 10h ;color text)
init5: mov ax,es:[4Ah] ;Get number of columns in AX
shl ax,1 ;Compute bytes per video line
mov line_length,ax ;Store it in LINE_LENGTH
mov ax,es:[4Eh] ;Save the starting address
mov video_offset,ax ;of the video buffer
mov ax,1A00h ;Branch if the system
int 10h ;contains a VGA video
cmp al,1Ah ;adapter
je init6
mov ah,12h ;Branch if the system does
mov bl,10h ;not contain an EGA video
int 10h ;adapter
cmp bl,10h
je init7
init6: mov al,es:[84h] ;Read the highest row number
mov maxrow,al ;from the BIOS data area
init7: ret
init_video endp
;****************************************************************************
; BUILD_TABLE fills in the MAP array by performing a series of tests to
; determine what type of video hardware is installed, where physical EMS
; pages are located, and what regions of upper memory contain RAM and ROM.
;****************************************************************************
build_table proc near
mov ax,cs ;Point ES to the code
mov es,ax ;segment
;
; Check for a VGA video adapter and fill in the A000 and B000 segments
; if a VGA is detected.
;
mov ax,1A00h ;Check for a VGA by calling
int 10h ;function 1A00h in the
cmp al,1Ah ;video BIOS
jne check_ega ;Branch if no VGA
mov di,offset map ;Fill the first 64 bytes of
mov al,"V" ;the MAP array with "V"s
mov cx,64
rep stosb
jmp check_ems ;Branch to EMS check
;
; If there's an EGA installed, fill in the MAP array based on whether the
; EGA is attached to a monochrome or color monitor and how much video RAM
; it contains.
;
check_ega: mov ah,12h ;Check for an EGA adapter
mov bl,10h ;and branch if there's not
int 10h ;one installed
cmp bl,10h
je check_cga
mov ax,40h ;Point ES to the BIOS data
mov es,ax ;area
cmp byte ptr es:[49h],7 ;Branch if mode number is
jne ega_color ;other than 7
mov ax,cs ;Point ES back to the code
mov es,ax ;segment
mov di,offset map+32 ;For an EGA attached to a
mov al,"V" ;monochrome monitor, fill
mov cx,16 ;in B000 through B3FF if
cmp bl,0 ;the EGA contains 64K of
jne ega1 ;RAM, or B000 through
mov cx,8 ;B7FF if there's more
ega1: rep stosb ;than 64K on board
mov di,offset map ;For an EGA attached to a
mov al,"V" ;monochrome monitor, fill
mov cx,32 ;in A000 through A7FF if
cmp bl,0 ;the EGA contains 64K of
jne ega2 ;RAM, or A000 through
mov cx,16 ;AFFF if there's more
ega2: rep stosb ;than 64K on board
jmp short check_cga ;Check for a CGA, too
ega_color: mov ax,cs ;Point ES back to the code
mov es,ax ;segment
mov di,offset map+48 ;For an EGA attached to a
mov al,"V" ;color monitor, fill in
mov cx,16 ;B800 through BBFF if the
cmp bl,0 ;EGA contains 64K of RAM,
jne ega3 ;or B800 through BFFF if
mov cx,8 ;there's more than 64K
ega3: rep stosb ;on board
mov di,offset map ;For an EGA attached to a
mov al,"V" ;color monitor, fill in
mov cx,32 ;A000 through A7FF if the
cmp bl,0 ;EGA contains 64K of RAM,
jne ega4 ;or A000 through AFFF if
mov cx,16 ;there's more than 64K
ega4: rep stosb ;on board
;
; Check for a CGA, MDA, or Hercules card and fill the MAP array accordingly.
;
check_cga: mov dx,3D4h ;Write a "V" to bytes 48
call test_crtc ;through 55 of the MAP
jc check_mda ;array if there's a
mov di,offset map+48 ;CGA installed
mov al,"V"
mov cx,8
rep stosb
check_mda: mov dx,3B4h ;Write a "V" to bytes 32
call test_crtc ;through 33 of the MAP
jc check_ems ;array if there's an
mov di,offset map+32 ;MDA installed
mov al,"V"
mov cx,2
rep stosb
mov dx,3BAh ;Determine if a Hercules
in al,dx ;video adapter is installed
mov ah,al ;by seeing if bit 7 of the
and ah,80h ;CRTC's Status Register
mov cx,8000h ;changes
hgc1: in al,dx
and al,80h
cmp ah,al
jne hgc2 ;Exit loop if value changed
loop hgc1 ;Try again if it didn't
jmp short check_ems ;Branch if test was negative
hgc2: mov di,offset map+32 ;Fill the entire B000 area
mov al,"V" ;of the MAP array with "V"s
mov cx,32 ;if a Hercules adapter was
rep stosb ;detected
;
; Check for the presence of an expanded memory manager (EMM) and locate
; the EMS page frame if an EMM is installed.
;
check_ems: mov ax,3567h ;See if there is an EMM
int 21h ;installed by checking
mov di,10 ;for the string "EMMXXXX0"
mov si,offset devname ;10 bytes past where the
mov cx,8 ;interrupt 67h vector
repe cmpsb ;points to
jne check_arom ;Branch if no EMM detected
mov ax,cs ;Point ES back to the code
mov es,ax ;segment
mov ah,40h ;Now make sure the EMM
int 67h ;hardware is present
cmp ah,00h ;and operational
jne check_arom ;Branch if it's not
;
; Get EMS page frame information.
;
mov ah,41h ;Determine segment address
int 67h ;of the EMS page frame by
cmp ah,00h ;calling function 41h
jne check_arom
cmp bx,0A000h ;Branch if page frame is
jb check_arom ;below A000h
sub bx,0A000h ;Compute corresponding
mov cl,7 ;offset into MAP array
shr bx,cl
mov di,offset map
add di,bx
mov al,"E" ;Write "E" to 32 consecutive
mov cx,32 ;blocks to identify the
rep stosb ;page frame
;
; Check for adapter ROM by inspecting the first two bytes of every 2K
; block between segments C000 and F400 for an adapter ROM signature.
;
check_arom: mov si,64 ;SI holds index into MAP
arom1: cmp byte ptr [si+offset map],20h ;Skip this block if
jne next_block ;already checked
mov ax,si ;Compute next segment address
mov cl,7 ;by shifting SI 7 bits left
shl ax,cl ;and adding A000h
add ax,0A000h
mov es,ax ;Transfer result to ES
cmp word ptr es:[0],0AA55h ;Branch if no signature is
jne next_block ;found
mov al,es:[2] ;Get number of blocks
cbw ;Convert byte to word
mov cl,9 ;Compute length of adapter
shl ax,cl ;ROM in bytes
mov cx,ax ;Transfer result to CX
xor al,al ;Zero AL and DI
xor di,di
arom3: add al,es:[di] ;Validate the ROM by summing
inc di ;all the bytes in it,
loop arom3 ;modulo 100h
or al,al ;Not a valid ROM module if
jnz next_block ;the result isn't zero
mov al,es:[2] ;Get number of blocks
add al,3 ;Compute number of 2K
shr al,1 ;blocks the module
shr al,1 ;comprises
mov cl,al ;Transfer result to CL
xor ch,ch ;Byte to word in CX
push cx ;Save the result
mov ax,cs ;Write "R"s to affected
mov es,ax ;areas of the MAP array
mov di,si
add di,offset map
mov al,"R"
rep stosb
pop cx ;Retrieve block count
add si,cx ;Add block count to SI
dec si ;Decrement before proceeding
next_block: cmp si,168 ;Increment SI and loop back
jae check_ram ;if it's less than 168,
inc si ;which corresponds to
jmp arom1 ;segment F400
;
; Check all 2K blocks that haven't been analyzed yet for ROM or RAM.
;
check_ram: call disable_nmi ;Disable NMI
xor cx,cx ;Initialize counter
mov dx,cs ;DX holds segment address
ram1: push cx ;Save count
mov si,cx ;Transfer count to SI
cmp byte ptr [si+offset map],20h ;Skip this block if
je ram2 ;already checked
jmp next_region
ram2: mov cl,7 ;Compute next segment address
shl si,cl ;by shifting SI 7 bits left
add si,0A000h ;and adding A000h
mov bx,si ;Save result in BX
mov ds,bx ;Copy the block to local
assume ds:nothing ;memory
xor si,si
mov di,offset lastbyte
mov es,dx
mov cx,1024
cli ;Interrupts off!!!
rep movsw
mov ds,dx
assume ds:code
mov es,bx ;Copy test data to the
xor di,di ;block in upper memory
mov si,0100h
mov cx,1024
rep movsw
mov ds,bx ;Copy the block to local
assume ds:nothing ;memory again
xor si,si
mov di,offset lastbyte+2048
mov es,dx
mov cx,1024
rep movsw
mov ds,dx
assume ds:code
mov es,bx ;Restore the block's
xor di,di ;original contents
mov si,offset lastbyte
mov cx,1024
rep movsw
sti ;Interrupts on!!!
mov si,0100h ;Compare what was written
mov di,offset lastbyte+2048 ;to what was read back to
mov es,dx ;determine if this block
mov cx,1024 ;is populated with RAM
repe cmpsw
jne ram3 ;Branch if they're not equal
pop si ;Retrieve count from stack
push si ;Push it back on for later
mov byte ptr [si+offset map],"+" ;Mark block as RAM
jmp short next_region ;Branch and continue
ram3: mov si,offset lastbyte ;Compare the two sets of
mov di,offset lastbyte+2048 ;data read from the block
mov cx,1024 ;to determine if the block
repe cmpsw ;is populated with ROM
jne ram4 ;Branch if they're not equal
mov di,offset lastbyte ;See if all the bytes that
mov al,[di] ;were read have the same
mov cx,2048 ;value. If they do, then
repe scasb ;this probably isn't ROM.
je next_region
pop si ;Retrieve count from stack
push si ;Push it back on for later
mov byte ptr [si+offset map],"R" ;Mark block as ROM
jmp short next_region ;Branch and continue
ram4: pop si ;Retrieve count from stack
push si ;Push it back on for later
mov byte ptr [si+offset map],"U" ;Mark block with "U"
next_region: pop cx ;Retrieve count
inc cx ;Increment count
cmp cx,192 ;Loop until done
je build_exit
jmp ram1
build_exit: call enable_nmi ;Enable NMI
ret
build_table endp
;****************************************************************************
; DISABLE_NMI disables NMI.
;****************************************************************************
disable_nmi proc near
mov ax,0C400h ;Find out if this is a PS/2
int 15h
jc dnmi1
xor al,al ;Disable NMI on a PS/2
out 70h,al
jmp short $+2
jmp short $+2
in al,71h
jmp short dnmi_exit
dnmi1: in al,0A0h ;Disable NMI on a non-
jmp short $+2 ;PS/2
jmp short $+2
and al,7Fh
out 0A0h,al
dnmi_exit: ret
disable_nmi endp
;****************************************************************************
; ENABLE_NMI enables NMI.
;****************************************************************************
enable_nmi proc near
mov ax,0C400h ;Find out if this is a PS/2
int 15h
jc enmi1
mov al,80h ;Enable NMI on a PS/2
out 70h,al
jmp short $+2
jmp short $+2
in al,71h
jmp short enmi_exit
enmi1: in al,0A0h ;Enable NMI on a non-
jmp short $+2 ;PS/2
jmp short $+2
or al,80h
out 0A0h,al
enmi_exit: ret
enable_nmi endp
;****************************************************************************
; DRAW_SCREEN paints the screen.
;****************************************************************************
draw_screen proc near
call clear_screen ;Clear the screen
mov ah,title_color ;Write line 1 of the
mov dx,0012h ;header at the top
mov si,offset header1 ;of the screen
call write_string
mov ah,title_color ;Write line 2 of the
mov dx,010Ch ;header
mov si,offset header2
call write_string
mov ah,border_color ;Draw the border around
mov cx,0300h ;the window at the top
mov dx,104Fh ;of the screen
call drawbox
mov ax,0600h ;Clear the interior of
mov bh,back_color ;the window
mov cx,0401h
mov dx,0F4Eh
int 10h
mov ax,0600h ;Draw the shadow behind
mov bh,shadow_color ;the first subwindow
mov cx,0605h
mov dx,0E2Eh
int 10h
mov ax,0600h ;Draw the shadow behind
mov bh,shadow_color ;the second subwindow
mov cx,0635h
mov dx,0E4Bh
int 10h
mov ax,0600h ;Draw the first subwindow
mov bh,fore_color
mov cx,0504h
mov dx,0D2Dh
int 10h
mov ax,0600h ;Draw the second subwindow
mov bh,fore_color
mov cx,0534h
mov dx,0D4Ah
int 10h
mov ah,fore_color ;Display segment addresses
mov dx,0705h
mov si,offset text1
call write_string
mov ah,fore_color
mov dx,0805h
mov si,offset text2
call write_string
mov ah,fore_color
mov dx,0905h
mov si,offset text3
call write_string
mov ah,fore_color
mov dx,0A05h
mov si,offset text4
call write_string
mov ah,fore_color
mov dx,0B05h
mov si,offset text5
call write_string
mov ah,fore_color
mov dx,0C05h
mov si,offset text6
call write_string
mov si,offset text7 ;Display "0" thru "F"
mov cx,16 ;above the first
dscr1: push cx ;subwindow
lodsb
mov dl,al
mov dh,06h
lodsb
mov ah,fore_color
call write_char
pop cx
loop dscr1
mov ah,rom_color ;Display "LEGEND"
mov dx,0635h
mov si,offset text8
call write_string
mov ah,rom_color ;Display legend labels
mov dx,0835h
mov si,offset text9
call write_string
mov ah,ram_color
mov dx,0935h
mov si,offset text10
call write_string
mov ah,video_color
mov dx,0A35h
mov si,offset text11
call write_string
mov ah,ems_color
mov dx,0B35h
mov si,offset text12
call write_string
mov ah,unk_color
mov dx,0C35h
mov si,offset text12x
call write_string
mov ah,fore_color ;Display legend notes
mov dx,083Bh
mov si,offset text13
call write_string
mov ah,fore_color
mov dx,093Bh
mov si,offset text14
call write_string
mov ah,fore_color
mov dx,0A3Bh
mov si,offset text15
call write_string
mov ah,fore_color
mov dx,0B3Bh
mov si,offset text16
call write_string
mov ah,fore_color
mov dx,0C3Bh
mov si,offset text17
call write_string
mov ah,note_color ;Display notes at the
mov dx,1200h ;bottom of the screen
mov si,offset text18
call write_string
mov ah,note_color
mov dx,1300h
mov si,offset text19
call write_string
mov ah,note_color
mov dx,1400h
mov si,offset text20
call write_string
mov ah,note_color
mov dx,1500h
mov si,offset text21
call write_string
mov ah,note_color
mov dx,1600h
mov si,offset text22
call write_string
mov ah,rom_color ;Highlight text in the
mov dx,1203h ;notes area
mov si,offset text9
call write_string
mov ah,ram_color
mov dx,1303h
mov si,offset text10
call write_string
mov ah,unk_color
mov dx,1410h
mov si,offset text12x
call write_string
mov ah,title_color ;Display "Press Esc to
mov dx,181Eh ;exit"
mov si,offset text23
call write_string
ret
draw_screen endp
;****************************************************************************
; DRAW_MAP draws the memory map stored in the MAP array.
;****************************************************************************
draw_map proc near
mov dx,0C0Ah ;Initialize DX
mov si,offset map ;Point SI to MAP array
mov cx,6 ;Do six rows, saving CX and
dmap1: push cx ;and DX prior to each pass
push dx ;through the loop
mov cx,4 ;Do four sets of columns in
dmap2: push cx ;each row, each time saving
push dx ;CX and DX at the beginning
mov cx,8 ;Eight characters per set
dmap3: push cx ;Save CX and DX
push dx
lodsb ;Get the MAP character
mov ah,fore_color ;Load the appropriate video
cmp al,"R" ;attribute in AH
jne dmap4
mov ah,rom_color
jmp short dmap8
dmap4: cmp al,"+"
jne dmap5
mov ah,ram_color
jmp short dmap8
dmap5: cmp al,"V"
jne dmap6
mov ah,video_color
jmp short dmap8
dmap6: cmp al,"E"
jne dmap7
mov ah,ems_color
jmp short dmap8
dmap7: cmp al,"U"
jne dmap8
mov ah,unk_color
dmap8: call write_char ;Output the character
pop dx ;Retrieve row and column
inc dl ;Increment the column number
pop cx ;Retrieve count in CX
loop dmap3 ;Loop until done
pop dx ;Retrieve row and column
add dl,9 ;Add 9 to the column number
pop cx ;Retrieve set count in CX
loop dmap2 ;Loop until done
pop dx ;Retrieve row and column
dec dh ;Decrement the row number
mov dl,0Ah ;Reinitialize column number
pop cx ;Retrieve row count in CX
loop dmap1 ;Loop until done
ret
draw_map endp
;****************************************************************************
; TEST_CRTC tests for the presence of a 6845-style CRT controller at the
; port address specified in DX. On return, carry is clear if a CRTC was
; detected, or set if no CRTC was found.
;****************************************************************************
test_crtc proc near
mov al,0Fh ;Set CRTC address register to
out dx,al ;0Fh (Cursor Address Low)
jmp short $+2 ;I/O delay
jmp short $+2
inc dx ;Point DX to data register
in al,dx ;Read Cursor Address Low
mov ah,al ;Save result in AH
not al ;Flip the bits in AL
mov bl,al ;Save this result in BL
out dx,al ;Write the new value back
jmp short $+2 ;I/O delay
jmp short $+2
in al,dx ;Read Cursor Address Low
jmp short $+2 ;I/O delay
jmp short $+2
xchg al,ah ;Swap AH and AL
out dx,al ;Restore original value
cmp ah,bl ;No CRTC here is AH is not
jne test1 ;equal to BL
clc ;Clear the carry flag
ret ;and return
test1: stc ;Set the carry flag
ret ;and return
test_crtc endp
;****************************************************************************
; CLEAR_SCREEN clears the screen. Set MAXROW equal to the number of rows
; displayed minus 1 before calling this procedure.
;****************************************************************************
clear_screen proc near
mov ax,0600h
mov bh,07h
mov cx,0000h
mov dh,maxrow
mov dl,4Fh
int 10h
ret
clear_screen endp
;****************************************************************************
; DRAWBOX draws a box in text mode using single-line graphics characters.
; On entry, CX holds the row and column address of the upper left corner,
; and DX holds the row and column address of the lower right corner. AH
; holds the video attribute used to draw the box.
;****************************************************************************
rows dw 0 ;Number of rows
columns dw 0 ;Number of columns
drawbox proc near
sub dh,ch ;Compute the number of rows
dec dh ;inside the box
mov byte ptr rows,dh
sub dl,cl ;Then compute the number of
dec dl ;columns
mov byte ptr columns,dl
push ax ;Save video attribute
mov dx,cx ;Place starting address in DX
call compute_address ;Compute the memory address
mov di,ax ;Transfer result to DI
mov es,video_segment ;Point ES to the video buffer
pop ax ;Retrieve video attribute
push di ;Save video buffer address
mov al,0DAh ;Draw the upper left corner
stosw ;of the box
mov al,0C4h ;Draw the upper horizontal
mov cx,columns
rep stosw
mov al,0BFh ;Draw the upper right corner
stosw ;of the box
sub di,2 ;Point DI to the end of the
add di,line_length ;second row of the box
mov cx,rows ;Draw right vertical
call draw_vertical
mov al,0D9h ;Draw the lower right corner
stosw ;of the box
pop di ;Retrieve address
add di,line_length ;Point DI to the second row
mov cx,rows ;Draw left vertical
call draw_vertical
mov al,0C0h ;Draw the lower left corner
stosw ;of the box
mov al,0C4h ;Draw the lower horizontal
mov cx,columns
rep stosw
ret
drawbox endp
;****************************************************************************
; DRAW_VERTICAL draws a vertical line. On entry, ES:DI points to the
; location in the video buffer, AH holds the video attribute, and CX
; holds the length of the line in rows.
;****************************************************************************
draw_vertical proc near
mov al,0B3h ;Load AL with ASCII code
dv_loop: stosw ;Write one character
sub di,2 ;Point DI to the character
add di,line_length ;cell on the next row
loop dv_loop ;Loop until done
ret
draw_vertical endp
;****************************************************************************
; WRITE_STRING writes an ASCIIZ string at the row and column address
; specified in DH and DL. On entry, AH contains the video attribute and
; DS:SI points to the string.
;****************************************************************************
write_string proc near
push ax ;Save video attribute
call compute_address ;Compute the memory address
mov di,ax ;Transfer result to DI
mov es,video_segment ;Point ES to the video buffer
pop ax ;Retrieve video attribute
ws_loop: lodsb ;Get a character
or al,al ;Exit if it's zero
jz ws_exit
stosw ;Display it
jmp ws_loop ;Loop back for more
ws_exit: ret
write_string endp
;****************************************************************************
; WRITE_CHAR writes a character and attribute at the row and column
; address specified in DH and DL. On entry, AH holds the video attribute
; and AL holds the character's ASCII code.
;****************************************************************************
write_char proc near
push ax ;Save video attribute
call compute_address ;Compute the memory address
mov di,ax ;Transfer result to DI
mov es,video_segment ;Point ES to the video buffer
pop ax ;Retrieve video attribute
stosw ;Write the character and
ret ;attribute and exit
write_char endp
;****************************************************************************
; COMPUTE_ADDRESS returns in AX the video buffer address that corresponds
; to the row and column number passed in DH and DL. Before this procedure
; is called, LINE_LENGTH must contain the number of bytes per video line
; and VIDEO_OFFSET must contain the offset within the video buffer of the
; current video page.
;****************************************************************************
compute_address proc near
mov cl,dl ;Save DL in CL
mov al,dh ;Get starting row in AL
cbw ;Convert byte to word in AX
mul line_length ;Multiply by bytes per row
mov dl,cl ;Load DL with column number
shl dx,1 ;Multiply starting column by 2
add ax,dx ;Add it to AX
add ax,video_offset ;Add video buffer offset
ret
compute_address endp
lastbyte label byte
code ends
end begin